
package com.vxdata.utils.modules.weixin.service.impl;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.vxdata.common.core.domain.AjaxResult;
import com.vxdata.common.core.domain.entity.SysUser;
import com.vxdata.common.core.domain.entity.WxUser;
import com.vxdata.common.utils.StringUtils;
import com.vxdata.framework.web.service.SysLoginService;
import com.vxdata.system.service.ISysRoleService;
import com.vxdata.system.service.ISysUserService;
import com.vxdata.utils.modules.weixin.service.IWxUserService;
import com.vxdata.utils.modules.weixin.utils.CodeResult;
import com.vxdata.utils.modules.weixin.utils.WXBizMsgCrypt;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Set;

@Slf4j
@Service
public class ApiLoginServiceImpl {
    @Value("${applet.appId}")
    String appId;
    @Value("${applet.secret}")
    String secret;
    @Autowired
    private ISysUserService userService;
    @Autowired
    private ISysRoleService roleService;
    @Autowired
    private IWxUserService wxUserService;
    @Resource
    private SysLoginService loginService;

    private final static String WECHAT_MINI_PROGRAME_URL = "https://api.weixin.qq.com/sns/jscode2session";

    /**
     * 微信登录
     *
     * @param paramMap
     * @return
     */
    public AjaxResult login(Map<String, String> paramMap) {
        // 登录验证的code
        String code = paramMap.get("code");
        // ASE加密内容
        String encryptedData = paramMap.get("encryptedData");
        // ASE偏移量
        String iv = paramMap.get("iv");
        if (StringUtils.isEmpty(code) || StringUtils.isEmpty(encryptedData) || StringUtils.isEmpty(iv)) {
            return AjaxResult.error("code or encryptedData or iv is null");
        }
        CodeResult codeResult = getPhone(code, encryptedData, iv);
        return AjaxResult.success(codeResult);
    }


    /**
     * 登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程。更多使用方法详见 小程序登录
     * 相关文档: https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
     *
     * @param code          登录时获取的 code
     * @param encryptedData
     * @param iv
     * @return
     */
    public CodeResult getPhone(String code, String encryptedData, String iv) {
        // 登录验证请求地址
        StringBuilder url = new StringBuilder();
        url.append(WECHAT_MINI_PROGRAME_URL);
        url.append("?appid=");
        url.append(appId);
        url.append("&secret=");
        url.append(secret);
        url.append("&js_code=");
        url.append(code);
        url.append("&grant_type=authorization_code");
        String body = HttpUtil.get(url.toString());
        CodeResult result = null;
        if (StringUtils.isNotEmpty(body)) {
            result = JSON.parseObject(body, CodeResult.class);
            // 请求成功
            if (result.getErrcode() == 0) {
                // aes解密获取用户的手机号
                String data = WXBizMsgCrypt.decrypt(result.getSession_key(), encryptedData, iv);
                JSONObject json = JSON.parseObject(data);
                if (json != null && json.containsKey("purePhoneNumber")) {
                    String phone = json.getString("purePhoneNumber");
                    result.setPhone(phone);
                    WxUser wxUser = new WxUser();
                    WxUser one = wxUserService.lambdaQuery().eq(WxUser::getPhone, phone).one();
                    if (one != null) {
                        wxUser = one;
                    }
                    wxUser.setOpenId(result.getOpenid());
                    wxUser.setSessionKey(result.getSession_key());
                    wxUser.setOpenId(result.getOpenid());
                    wxUser.setPhone(phone);
                    wxUser.setUserName("");
                    // 验证是否系统用户
                    SysUser sysUser = userService.selectUserByPhone(phone);
                    if (sysUser != null) {
                        Set<String> roles = roleService.selectRolePermissionByUserId(sysUser.getUserId());
                        result.setRoles(roles);
                        wxUser.setUserName(sysUser.getUserName());
                    }
                    if (one != null) {
                        wxUserService.updateById(wxUser);
                    } else {
                        wxUserService.save(wxUser);
                    }
                    String token = loginService.wxLogin(wxUser);
                    result.setToken(token);
                    result.setOpenid(null);
                    result.setSession_key(null);
                    return result;
                }
            }
        }
        return result;
    }
}
